package io.itit.ecp.admin.provide.action.controller.miniprogram;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.StrBuilder;
import icu.mhb.mybatisplus.plugln.extend.Joins;
import io.itit.ecp.admin.common.enums.AIModelRunningModeEnums;
import io.itit.ecp.admin.provide.action.resp.miniprogram.RunningModeAnalysisResp;
import io.itit.ecp.admin.provide.action.resp.miniprogram.RunningModeCompareResp;
import io.itit.ecp.admin.server.entity.AIModelEntity;
import io.itit.ecp.admin.server.entity.RunningModeDataEntity;
import io.itit.ecp.admin.server.service.IAIModelService;
import io.itit.ecp.admin.server.service.IRunningModeDataService;
import io.itit.grass.common.provide.action.resp.ResultResp;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * AI 模型管理
 */
@Api(tags = "AI 模型管理")
@RestController
@RequiredArgsConstructor
@RequestMapping("/mini/aimodel")
public class MiniAiModelController {

    @Autowired
    private IAIModelService iaiModelService;

    @Autowired
    private IRunningModeDataService runningModeDataService;

    @ApiOperation("查询介绍")
    @GetMapping("introduce")
    public ResultResp<Map<String, Object>> introduce(@RequestParam String sceneProjectId) {
        AIModelEntity aiModelEntity = iaiModelService.lambdaQuery()
                .eq(AIModelEntity::getSceneProjectId, sceneProjectId)
                .orderByDesc(AIModelEntity::getCreateTm)
                .one();
        return ResultResp.success(Collections.singletonMap("remark", Objects.isNull(aiModelEntity) ? null : aiModelEntity.getRemark()));
    }


    @Data
    public static class RuntimeData {

        private Integer count;

        private String runningMode;

        public String getTime() {
            if (Objects.isNull(count)) {
                return null;
            }
            int hour = count / 4;
            int minute = count % 4;
            StrBuilder sb = new StrBuilder();
            if (hour > 0) {
                sb.append(hour).append("h");
            }
            if (minute > 0) {
                sb.append(minute * 15).append("m");
            }
            return sb.toString();
        }
    }

    /**
     * AI模型的运行时间
     */
    @ApiOperation("AI模型的运行时间")
    @GetMapping("runtime")
    public ResultResp<List<RuntimeData>> runtime(@RequestParam String sceneProjectId,
                                                 @RequestParam(required = false) String startTime,
                                                 @RequestParam(required = false) String endTime) {
        LocalDateTime start = StringUtils.isNotEmpty(startTime) ? LocalDate.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MIN) : null;
        LocalDateTime end = StringUtils.isNotEmpty(endTime) ? LocalDate.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MAX) : LocalDateTime.now();
        List<RuntimeData> runtimeDataList = Joins.of(RunningModeDataEntity.class)
                .selectAs(builder -> builder.add("COUNT(id)", "count", false)
                        .add("running_mode", "runningMode", false))
                .eq(StringUtils.isNotEmpty(sceneProjectId), RunningModeDataEntity::getSceneProjectId, sceneProjectId)
                .ge(Objects.nonNull(start), RunningModeDataEntity::getSolidifyDate, start)
                .le(RunningModeDataEntity::getSolidifyDate, end)
                .groupBy(RunningModeDataEntity::getRunningMode)
                .joinList(RuntimeData.class);
        return ResultResp.success(runtimeDataList);
    }

    /**
     * AI模型对比
     */
    @ApiOperation("AI模型对比")
    @GetMapping("compare")
    public ResultResp<List<RunningModeCompareResp>> compare(@RequestParam String sceneProjectId,
                                                            @RequestParam(required = false) String startTime,
                                                            @RequestParam(required = false) String endTime) {
        LocalDateTime start = StringUtils.isNotEmpty(startTime) ? LocalDate.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MIN) : null;
        LocalDateTime end = StringUtils.isNotEmpty(endTime) ? LocalDate.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MAX) : LocalDateTime.now();
        List<RunningModeDataEntity> runtimeDataList = Joins.of(RunningModeDataEntity.class)
                .selectAs(builder ->
                        builder.add("SUM(carbon_value)", "carbonValue", false)
                                .add("SUM(income_value)", "incomeValue", false)
                                .add("SUM(save_electricity_costs)", "saveElectricityCosts", false)
                                .add("running_mode", "runningMode", false))
                .eq(StringUtils.isNotEmpty(sceneProjectId), RunningModeDataEntity::getSceneProjectId, sceneProjectId)
                .ge(Objects.nonNull(start), RunningModeDataEntity::getSolidifyDate, start)
                .le(RunningModeDataEntity::getSolidifyDate, end)
                .groupBy(RunningModeDataEntity::getRunningMode)
                .joinList(RunningModeDataEntity.class);
        List<RunningModeCompareResp> resultList = new ArrayList<>();
        for (AIModelRunningModeEnums modeEnums : AIModelRunningModeEnums.values()) {
            RunningModeDataEntity modeDataEntity = runtimeDataList.stream().filter(item -> StringUtils.equals(item.getRunningMode(), modeEnums.getValue()))
                    .findFirst()
                    .orElse(null);
            resultList.add(new RunningModeCompareResp().setRunningMode(modeEnums.getValue())
                    .setRunningModeName(modeEnums.getLabel())
                    .setCarbonValue(Objects.isNull(modeDataEntity) || Objects.isNull(modeDataEntity.getCarbonValue()) ? BigDecimal.ZERO : modeDataEntity.getCarbonValue().setScale(2, RoundingMode.HALF_DOWN))
                    .setIncomeValue(Objects.isNull(modeDataEntity) || Objects.isNull(modeDataEntity.getIncomeValue()) ? BigDecimal.ZERO : modeDataEntity.getIncomeValue().setScale(2, RoundingMode.HALF_DOWN))
                    .setSaveElectricityCosts(Objects.isNull(modeDataEntity) || Objects.isNull(modeDataEntity.getSaveElectricityCosts()) ? BigDecimal.ZERO : modeDataEntity.getSaveElectricityCosts().setScale(2, RoundingMode.HALF_DOWN)));
        }
        return ResultResp.success(resultList);
    }

    /**
     * AI模型分析
     *
     * @param type （1: 减排量，2: 费用，3：收益）
     */
    @ApiOperation("AI模型分析")
    @GetMapping("analysis")
    public ResultResp<List<RunningModeAnalysisResp>> analysis(@RequestParam String sceneProjectId,
                                                              @RequestParam String type,
                                                              @RequestParam(required = false) String startTime,
                                                              @RequestParam(required = false) String endTime) {
        LocalDateTime start = StringUtils.isNotEmpty(startTime) ? LocalDate.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MIN) : null;
        LocalDateTime end = StringUtils.isNotEmpty(endTime) ? LocalDate.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MAX) : LocalDateTime.now();
        List<RunningModeDataEntity> runtimeDataList = Joins.of(RunningModeDataEntity.class)
                .select(RunningModeDataEntity::getCarbonValue,
                        RunningModeDataEntity::getIncomeValue,
                        RunningModeDataEntity::getSaveElectricityCosts,
                        RunningModeDataEntity::getSolidifyDate, RunningModeDataEntity::getRunningMode)
                .eq(StringUtils.isNotEmpty(sceneProjectId), RunningModeDataEntity::getSceneProjectId, sceneProjectId)
                .ge(Objects.nonNull(start), RunningModeDataEntity::getSolidifyDate, start)
                .le(RunningModeDataEntity::getSolidifyDate, end)
                .joinList(RunningModeDataEntity.class);
        List<RunningModeAnalysisResp> dataList = new ArrayList<>();
        Map<String, List<RunningModeDataEntity>> runningModeMap = runtimeDataList.stream()
                .collect(Collectors.groupingBy(RunningModeDataEntity::getRunningMode));
        for (AIModelRunningModeEnums modeEnums : AIModelRunningModeEnums.values()) {
            List<RunningModeDataEntity> modeDataEntityList = runningModeMap.getOrDefault(modeEnums.getValue(), Collections.emptyList());
            LinkedHashMap<String, List<RunningModeDataEntity>> solidifyDataMap = modeDataEntityList.stream()
                    .collect(Collectors.groupingBy(item -> DateUtil.format(item.getSolidifyDate(), "yyyy-MM-dd HH:00"), LinkedHashMap::new, Collectors.toList()));
            List<RunningModeAnalysisResp.DataItem> dataItems = new ArrayList<>();
            for (Map.Entry<String, List<RunningModeDataEntity>> entry : solidifyDataMap.entrySet()) {
                String date = entry.getKey();
                BigDecimal value = entry.getValue().stream().map(item -> {
                    if (StringUtils.equals(type, "1")) {
                        return item.getCarbonValue();
                    } else if (StringUtils.equals(type, "2")) {
                        return item.getIncomeValue();
                    } else if (StringUtils.equals(type, "3")) {
                        return item.getSaveElectricityCosts();
                    }
                    return BigDecimal.ZERO;
                }).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_DOWN);
                dataItems.add(new RunningModeAnalysisResp.DataItem().setTime(date).setValue(value));
            }
            RunningModeAnalysisResp analysisResp = new RunningModeAnalysisResp()
                    .setName(modeEnums.getLabel())
                    .setValue(modeEnums.getValue())
                    .setData(dataItems);
            dataList.add(analysisResp);
        }
        return ResultResp.success(dataList);

    }
}
